using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Engine;
using Engine.Serialization;
using Game;
using XmlUtilities;

namespace RuthlessConquest {
    public static class SettingsManager {
        //public const string m_settingsFileName = "app:/doc/RCSettings.xml";
        public static Faction publicFaction;
        public static float publicDefaultFleetStrength;
        public static float publicMusicVolume;
        public static float publicSfxVolume;

        public static Version LastLaunchedVersion { get; set; }
        public static string PlayerName { get; set; }
        public static Guid PlayerGuid { get; set; }

        public static Faction Faction {
            get => publicFaction;
            set => publicFaction = (Faction)MathUtils.Clamp((int)value, 0, 5);
        }

        public static float DefaultFleetStrength {
            get => publicDefaultFleetStrength;
            set => publicDefaultFleetStrength = MathUtils.Clamp(value, 0.2f, 1f);
        }

        public static bool ShowFlags { get; set; }
        public static bool DontShowInstructions { get; set; }
        public static bool InstructionsShown { get; set; }

        public static int LastColorScheme { get; set; }

        public static float MusicVolume {
            get => publicMusicVolume;
            set => publicMusicVolume = MathUtils.Saturate(value);
        }

        public static float SfxVolume {
            get => publicSfxVolume;
            set => publicSfxVolume = MathUtils.Saturate(value);
        }

        public static int PresentationInterval { get; set; }
        public static float MinimumHoldDuration { get; set; }
        public static float MinimumDragDistance { get; set; }
        public static float GamepadDeadZone { get; set; }
        public static float GamepadCursorSpeed { get; set; }
        public static string MotdUpdateUrl { get; set; }
        public static string MotdBackupUpdateUrl { get; set; }
        public static bool MotdUseBackupUrl { get; set; }
        public static double MotdUpdatePeriodHours { get; set; }
        public static DateTime MotdLastUpdateTime { get; set; }
        public static string MotdLastDownloadedData { get; set; }
        public static bool DisplayFpsCounter { get; set; }
        public static bool DisplayFpsRibbon { get; set; }
        public static bool UpsideDownLayout { get; set; }

        public static List<string> LobbyServers {
            get => field;
            set {
                field = value;
                ServersManager.StopServerDiscovery();
            }
        }

        public static bool DisplayOptimalResultOfShipSent { get; set; }
        public static bool DisplayProductionRateOfPlanets { get; set; }

        public static bool DisplayPlayerStatistics { get; set; }
        public static bool DisplayMoreNotices { get; set; }

        public static void Initialize() {
            PlayerName = string.Empty;
            PlayerGuid = Guid.NewGuid();
            Faction = (Faction)new Random().Int(6);
            DefaultFleetStrength = 0.6f;
            ShowFlags = true;
            LastColorScheme = new Random().Int();
            publicMusicVolume = 0.5f;
            publicSfxVolume = 1f;
            PresentationInterval = 1;
            GamepadDeadZone = 0.16f;
            GamepadCursorSpeed = 1f;
            MotdUpdateUrl = "https://scresdir.appspot.com/motd/RuthlessConquest/Motd-{0}.zip";
            MotdBackupUpdateUrl = "https://scresdir.appspot.com/motd/RuthlessConquest/Motd-{0}.zip";
            MotdUpdatePeriodHours = 12.0;
            MotdLastUpdateTime = DateTime.MinValue;
            MotdLastDownloadedData = string.Empty;
            //LoadSettings();
            MinimumHoldDuration = 0.3f;
            MinimumDragDistance = 15f;
            LobbyServers = [
                "ruthlessconquest.kaalus.com",
                "ruthlessconquest1.kaalus.com",
                "ruthlessconquest2.kaalus.com",
                "ruthlessconquest3.kaalus.com",
                "rcserver.schub.top"
            ];
            DisplayOptimalResultOfShipSent = false;
            DisplayProductionRateOfPlanets = false;
            DisplayPlayerStatistics = false;
            DisplayMoreNotices = false;
            //Window.Deactivated += SaveSettings;
        }

        public static void LoadSettings(XElement xElement) {
            try {
                //if (!Storage.FileExists(m_settingsFileName)) {
                //return;
                //}
                //using (Stream stream = Storage.OpenFile(m_settingsFileName, OpenFileMode.Read)) {
                foreach (XElement item in xElement.Elements()) {
                    string name = "<unknown>";
                    try {
                        name = XmlUtils.GetAttributeValue<string>(item, "Name");
                        string attributeValue = XmlUtils.GetAttributeValue<string>(item, "Value");
                        PropertyInfo propertyInfo = (from pi in typeof(SettingsManager).GetRuntimeProperties()
                            where pi.Name == name
                                && pi.GetMethod != null
                                && pi.GetMethod.IsStatic
                                && pi.GetMethod.IsPublic
                                && pi.SetMethod != null
                                && pi.SetMethod.IsPublic
                            select pi).FirstOrDefault();
                        if (propertyInfo != null) {
                            object value = HumanReadableConverter.ConvertFromString(propertyInfo.PropertyType, attributeValue);
                            propertyInfo.SetValue(null, value, null);
                        }
                    }
                    catch (Exception ex) {
                        Log.Warning($"Setting \"{name}\" could not be loaded. Reason: {ex.Message}");
                    }
                }
                //}
                //Log.Information("Loaded settings.");
            }
            catch (Exception e) {
                ExceptionManager.ReportExceptionToUser("Loading settings failed.", e);
            }
        }

        public static void SaveSettings(XElement xElement) {
            try {
                //XElement xElement = new("Settings");
                foreach (PropertyInfo item in from pi in typeof(SettingsManager).GetRuntimeProperties()
                    where pi.GetMethod != null && pi.GetMethod.IsStatic && pi.GetMethod.IsPublic && pi.SetMethod != null && pi.SetMethod.IsPublic
                    select pi) {
                    try {
                        string value = HumanReadableConverter.ConvertToString(item.GetValue(null, null));
                        XElement node = XmlUtils.AddElement(xElement, "Setting");
                        XmlUtils.SetAttributeValue(node, "Name", item.Name);
                        XmlUtils.SetAttributeValue(node, "Value", value);
                    }
                    catch (Exception ex) {
                        Log.Warning($"Setting \"{item.Name}\" could not be saved. Reason: {ex.Message}");
                    }
                }
                //using (Stream stream = Storage.OpenFile(m_settingsFileName, OpenFileMode.Create)) {
                //XmlUtils.SaveXmlToStream(xElement, stream, null, true);
                //}
                //Log.Information("Saved settings");
            }
            catch (Exception e) {
                ExceptionManager.ReportExceptionToUser("Saving settings failed.", e);
            }
        }
    }
}